﻿using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Win32;
using ThePresenter.IO;
using ThePresenter.Polls;
using ThePresenter.Polls.Data;
using ThePresenter.Properties;
using ThePresenter.Windows.Controls;
using ThePresenter.Windows.Data;
using ThePresenter.Windows.Ink;
using ThePresenter.Windows.Input;

namespace ThePresenter.Windows
{
	/// <summary>
	/// Interaction logic for OverlayWindow.xaml
	/// </summary>
	public partial class OverlayWindow : Window
	{
		// TODO Add bool IsToggled dependency property and use in ToggleButton and handle changes with RoutedPropertyChangedEventHandler

		#region Fields

		/// <summary>
		/// Identifies the <see cref="Mode"/> dependency property.
		/// </summary>
		/// <value>The identifier for the <see cref="Mode"/> dependency property.</value>
		public static readonly DependencyProperty ModeProperty = DependencyProperty.Register("Mode", typeof(StartupMode), typeof(OverlayWindow));

		/// <summary>
		/// Identifies the <see cref=PaintArea"/> dependency property.
		/// </summary>
		/// <value>The identifier for the <see cref="PaintArea"/> dependency property.</value>
		public static readonly DependencyProperty PaintAreaProperty = DependencyProperty.Register("PaintArea", typeof(InkCanvas), typeof(OverlayWindow));

		/// <summary>
		/// Identifies the <see cref="Presentation"/> dependency property.
		/// </summary>
		/// <value>The identifier for the <see cref="Presentation"/> dependency property.</value>
		public static readonly DependencyProperty PresentationProperty = DependencyProperty.Register("Presentation", typeof(Presentation), typeof(OverlayWindow));

		/// <summary>
		/// Identifies the <see cref="ShapesLibrary"/> dependency property.
		/// </summary>
		/// <value>The identifier for the <see cref="ShapesLibrary"/> dependency property.</value>
		public static readonly DependencyProperty ShapesLibraryProperty = DependencyProperty.Register("ShapesLibrary", typeof(Data.ShapesLibrary), typeof(OverlayWindow));

		/// <summary>
		/// Identifies the <see cref="DrawingAttributes"/> dependency property.
		/// </summary>
		/// <value>The identifier for the <see cref="DrawingAttributes"/> dependency property.</value>
		public static readonly DependencyProperty DrawingAttributesProperty = DependencyProperty.Register("DrawingAttributes", typeof(InkCanvasAttributes), typeof(OverlayWindow));		

		/// <summary>
		/// Default editing mode
		/// </summary>
		InkCanvasEditingMode _DefaultEditingMode = InkCanvasEditingMode.Ink;

		/// <summary>
		/// Save information
		/// </summary>
		SaveInformation _SaveInformation;

		/// <summary>
		/// Adorner for Drag&Drop preview of shape
		/// </summary>
		DropPreviewAdorner _DragDropPreview;

		/// <summary>
		/// Counter for new shape.
		/// </summary>
		int NewShapeCounter = 0;

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the mode. This is a dependency property.
		/// </summary>
		/// <value>The mode.</value>
		public StartupMode Mode
		{
			get
			{
				return (StartupMode)GetValue(ModeProperty);
			}
			set
			{
				SetValue(ModeProperty, value);
			}
		}
		
		/// <summary>
		/// Gets or sets the paint area. This is a dependency property.
		/// </summary>
		/// <value>The paint area.</value>
		public InkCanvas PaintArea
		{
			get
			{
				return (InkCanvas)GetValue(PaintAreaProperty);
			}
			set
			{
				SetValue(PaintAreaProperty, value);
			}
		}

		/// <summary>
		/// Gets or sets the presentation. This is a dependency property.
		/// </summary>
		/// <value>The presentation.</value>
		public Presentation Presentation
		{
			get
			{
				return (Presentation)GetValue(PresentationProperty);
			}
			set
			{
				SetValue(PresentationProperty, value);
			}
		}

		/// <summary>
		/// Gets or sets the shapes library. This is a dependency property.
		/// </summary>
		/// <value>The shapes library.</value>
		public ShapesLibrary ShapesLibrary
		{
			get
			{
				return (ShapesLibrary)GetValue(ShapesLibraryProperty); 
			}
			set
			{
				SetValue(ShapesLibraryProperty, value);
			}
		}

		/// <summary>
		/// Gets or sets the drawing attributes. This is a dependency property.
		/// </summary>
		/// <value>The drawing attributes.</value>
		public InkCanvasAttributes DrawingAttributes
		{
			get
			{
				return (InkCanvasAttributes)GetValue(DrawingAttributesProperty);
			}
			set
			{
				SetValue(DrawingAttributesProperty, value);
			}
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes the <see cref="OverlayWindow"/> class.
		/// </summary>
		static OverlayWindow()
		{
			// Assign CTRL + SHIFT + S to Save As application command
			ApplicationCommands.SaveAs.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control | ModifierKeys.Shift));
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="OverlayWindow"/> class.
		/// </summary>
		public OverlayWindow()
		{
			InitializeComponent();

			DrawingAttributes = new InkCanvasAttributes() { EditingMode = InkCanvasEditingMode.Ink };

			Presentation = new Presentation();
			Presentation.PropertyChanged += new PropertyChangedEventHandler(Presentation_PropertyChanged);

#if NETWORK
			this.AllowsTransparency = false;
			// this.Title = this.RunningAs;
			this.Background = new SolidColorBrush(SystemColors.AppWorkspaceColor);
			this.ResizeMode = System.Windows.ResizeMode.CanResize;
			this.WindowState = System.Windows.WindowState.Normal;
			this.WindowStyle = System.Windows.WindowStyle.SingleBorderWindow;
			this.BorderBrush = new SolidColorBrush(Colors.Red);
#endif

#if !DEBUG
			Topmost = true;
#endif
		}

		#endregion

		#region UI Event Handlers

		/// <summary>
		/// Handles the Loaded event of the Window control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void Window_Loaded(object sender, RoutedEventArgs e)
		{
			ShapesLibrary = ShapesLibrary.Load(Settings.Default.ShapesLibraryPath);

			if (Mode == StartupMode.Watcher)
				ToggleVisibility();
		}

		/// <summary>
		/// Handles the Closed event of the Window control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void Window_Closed(object sender, EventArgs e)
		{
			if (ShapesLibrary != null)
			{
				ShapesLibrary.Save();
			}
		}

		/// <summary>
		/// Handles the KeyDown event of the Window control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
		private void Window_KeyDown(object sender, KeyEventArgs e)
		{
			SetEditingMode(e.KeyboardDevice.Modifiers);
		}

		/// <summary>
		/// Handles the KeyUp event of the Window control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
		private void Window_KeyUp(object sender, KeyEventArgs e)
		{
			SetEditingMode(e.KeyboardDevice.Modifiers);
		}

		/// <summary>
		/// Handles the MouseLeftButtonDown event of the Window control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
		private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			lock (this)
			{
				if (WindowState == WindowState.Maximized)
				{
					Width = ActualWidth;
					Height = ActualHeight;

					Left = Top = 0;

					WindowState = WindowState.Normal;
				}

				this.DragMove();
			}
		}

		/// <summary>
		/// Handles the MouseLeftButtonUp event of the Window control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
		private void Window_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
#if NETWORK
			return;
#endif
			lock (this)
			{
				if (WindowState == WindowState.Normal)
				{
					Width = Height = double.NaN;

					WindowState = WindowState.Maximized;
				}
			}
		}

		/// <summary>
		/// Handles the PropertyChanged event of the Presentation control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
		private void Presentation_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "SelectedSlide")
			{
				// TODO Do PaintArea = Presentation.SelectedSlide.Canvas via binding
				// PaintAreaHost Content = Binding ... Presentation.SelectedSlide.Canvas

				if (PaintArea != Presentation.SelectedSlide.Canvas)
				{
					PaintArea = Presentation.SelectedSlide.Canvas;
					PaintArea.AllowDrop = true;
				}
			}
		}

		/// <summary>
		/// Handles the Drop event of the PaintAreaHost control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
		private void PaintAreaHost_Drop(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(typeof(StrokeCollection)))
			{
				var strokes = e.Data.GetData(typeof(StrokeCollection)) as StrokeCollection;

				Point p = e.GetPosition(sender as UIElement);
				Matrix m = Matrix.Identity;
				Rect r = strokes.GetBounds();
				m.Translate(p.X - r.Width / 2, p.Y - r.Height / 2);

				var new_strokes = strokes.Clone();
				new_strokes.Transform(m, true);

				PaintArea.Strokes.Add(new_strokes);
			}

			PaintAreaHost_DragLeave(null, null);
		}

		/// <summary>
		/// Handles the DragEnter event of the PaintAreaHost control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
		private void PaintAreaHost_DragEnter(object sender, DragEventArgs e)
		{
			// Prevent unwanted slide changes while dragging
			Presentation.SlideLocked = true;

			if (!e.Data.GetDataPresent(typeof(StrokeCollection)))
			{
				e.Effects = DragDropEffects.None;
				return;
			}

			StrokeCollection strokes = e.Data.GetData(typeof(StrokeCollection)) as StrokeCollection;
			_DragDropPreview = new DropPreviewAdorner(PaintAreaHost, strokes, e.GetPosition(PaintAreaHost));
			AdornerLayer.GetAdornerLayer(PaintAreaHost).Add(_DragDropPreview);
		}

		/// <summary>
		/// Handles the DragLeave event of the PaintAreaHost control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.DragEventArgs"/> instance containing the event data.</param>
		private void PaintAreaHost_DragLeave(object sender, DragEventArgs e)
		{
			if (_DragDropPreview != null)
			{
				AdornerLayer.GetAdornerLayer(PaintAreaHost).Remove(_DragDropPreview);
				_DragDropPreview = null;
			}

			// Restore server following
			Presentation.SlideLocked = false;
		}

		/// <summary>
		/// Handles the SelectionChanged event of the Poll control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
		/// Client side event
		private void Poll_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (e.AddedItems.Count == 1)
			{
				Poll P = e.AddedItems[0] as Poll;

				if (P != null && P.QuestionData.QuestionType == QuestionType.Canvas)
				{
					// TODO: deselect presentation slide
//					Presentation.SelectedSlideIndex = -1;
					Slide S = ((CanvasQuestionData)P.QuestionData).GetSlide();
					Presentation.SelectedSlide = S;
				}
			}
		}

		/// <summary>
		/// Handles the MouseUp event of the Answer in Answers tree control.
		/// Server side handler
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
		private void Answer_MouseUp(object sender, MouseButtonEventArgs e)
		{
			AnswerData AD = (AnswerData)((FrameworkElement)sender).DataContext;

			if (AD != null && AD is CanvasAnswerData)
			{
				// TODO: deselect presentation slide
				Slide S = ((CanvasAnswerData)AD).GetSlide();
				Presentation.SelectedSlide = S;
			}
		}

		/// <summary>
		/// Handles the Click event of the AddToPresentationButton control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void AddToPresentationButton_Click(object sender, RoutedEventArgs e)
		{
			Slide S = new Slide();
			S.Background = Presentation.SelectedSlide.Background;
			S.Size = Presentation.SelectedSlide.Size;
			S.Strokes = Presentation.SelectedSlide.Strokes;
			this.Presentation.AddSlide(S);
			this.Presentation.SelectSlide(S);
		}

		///// <summary>
		///// Handles the Click event of the TakeScreenshotButton control.
		///// </summary>
		///// <param name="sender">The source of the event.</param>
		///// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		//private void TakeScreenshotButton_Click(object sender, RoutedEventArgs e)
		//{
		//    RenderTargetBitmap bitmap = new RenderTargetBitmap((int)ActualWidth, (int)ActualHeight, 96, 96, PixelFormats.Pbgra32);
		//    bitmap.Render(PaintArea);

		//    PngBitmapEncoder image = new PngBitmapEncoder();
		//    image.Frames.Add(BitmapFrame.Create(bitmap));

		//    using (Stream fs = File.Create("image.png"))
		//    {
		//        image.Save(fs);
		//    }

		//    Topmost = false;
		//    System.Diagnostics.Process.Start("image.png");
		//}

		#endregion

		#region Command bindings

		/// <summary>
		/// Handles the CanExecuteAnytime event of the Command command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Command_CanExecuteAnytime(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the New command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void New_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the New command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void New_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			lock (PaintAreaHost)
			{
				if (!PaintAreaHost.IsVisible)
					OverlayCommands.Toggle.Execute(null, this);
					//ToggleVisibility();

				Brush b = Brushes.White;

				if (object.Equals(e.Parameter, "Image")) // take screenshot
				{
					b = new ImageBrush(Helpers.TakeScreenshotImage(this.GetScreen().Bounds)); // new canvas with bg image

					GC.Collect(); // force to clear garbage
				}
				else if (e.Parameter is string && e.Parameter.ToString().StartsWith("#")) // hex string as color
				{
					b = new SolidColorBrush(Helpers.GetColorFromHexString(e.Parameter.ToString()));
				}
				else if (e.Parameter is Brush) // brush is directly provided
				{
					b = (Brush)e.Parameter;
				}

				PaintArea = new InkCanvas() { Width = this.ActualWidth, Height = this.ActualHeight, Background = b };
				Presentation.CreateSlide(PaintArea); // add new slide with ref to canvas to presentation
			}

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the Open command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Open_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			//e.CanExecute = IsInitialized && App.IO.Readers.Exists(i => i.CanBeShownInDialog()); // TODO Implement OverlayWindow.Open_CanExecute
			e.CanExecute = IsInitialized;
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the Open command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			// TODO Open: Ask if rewrite / append / cancel when have non empty presentation
			// now the slides are appended
			//MessageBox.Show(, , MessageBoxButton.YesNoCancel)

			OpenFileDialog dlg = new OpenFileDialog();
	
			dlg.Filter = String.Join("|", App.IO.Readers.Where(i => i.CanBeShownInDialog()).Select(i => i.Filter).ToArray());
			dlg.CheckFileExists = true;
			dlg.AddExtension = true;


			if (dlg.ShowDialog() == true)
			{
				// Find selected reader
				IReader reader = App.IO.Readers[dlg.FilterIndex - 1];

				if (reader != null)
				{
					DependencyObject config = reader.Configuration;

					if (config is BasicConfiguration)
					{
						var bc = config as BasicConfiguration;

						bc.TargetSize = new Size(this.ActualWidth, this.ActualHeight);
					}
					else if (config is Control)
					{
						// TODO Implement Show Configuration via special Window.ShowDialog()
					}


					var fs = new FileStream(dlg.FileName, FileMode.Open, FileAccess.Read); // cannot use using, because reading is made async
					{
						//ProgressDialog win = new ProgressDialog()
						//{
						//    Owner = this,
						//    IsIndeterminate = reader.SupportsProgressReporting == false
						//};

						//if (reader.SupportsProgressReporting)
						//{
						//    reader.PropertyChanged += new PropertyChangedEventHandler((_s, _e) =>
						//    {
						//        if (_e.PropertyName == "SlidesDone")
						//        {
						//            var percent = (double)reader.SlidesDone * 100 / reader.TotalSlides;

						//            win.Dispatcher.Invoke(new Action(() => win.Value = percent));
						//            //win.BeginAnimation(ProgressDialog.ValueProperty, new DoubleAnimation(percent, new Duration(TimeSpan.FromMilliseconds(250))));
						//        }
						//    });
						//}

						//win.Show(); // non blocking

						Presentation p = null;

						//ThreadStart start = delegate()
						//{
							reader.Read(config, fs, out p);

							//Dispatcher.Invoke(new Action(() =>
							//{
								Presentation.Author = p.Author;
								Presentation.Title = p.Title;

								foreach (var s in p.Slides)
								{
									Presentation.Slides.Add(s);
									//s.UpdateThumbnail();
								}

								foreach (var poll in p.Polls)
								{
									Presentation.Polls.Add(poll);
								}

								//win.Hide();
								//win.Close();
							//}));

							fs.Close();
							fs.Dispose();
						//};

						//var thread = new Thread(start) { Name = reader.GetType().Name };
						//thread.SetApartmentState(ApartmentState.STA);

						//thread.Start();


						//var worker = new BackgroundWorker();

						//worker.DoWork += new DoWorkEventHandler((_s, _e) => reader.Read(config, fs, out p));
						//worker.RunWorkerAsync();
						//worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((_s, _e) => ...
					}
				}
			}

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the Save command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = IsInitialized && Presentation != null && Presentation.Slides.Count > 0 && App.IO.Writers.Exists(i => i.CanBeShownInDialog());
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the Save command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (_SaveInformation == null)
			{
				SaveAs_Executed(sender, e);
			}
			else
			{
				// TODO Async Saving + show work indicator...
				Dispatcher.BeginInvoke((Action)delegate()
				{
					_SaveInformation.Save(Presentation);
				});
			}

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the SaveAs command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void SaveAs_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			Save_CanExecute(sender, e);
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the SaveAs command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SaveAs_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			SaveFileDialog dlg = new SaveFileDialog();

			dlg.Filter = String.Join("|", App.IO.Writers.Where(i => i.CanBeShownInDialog()).Select(i => i.Filter).ToArray());
			dlg.FileName = Presentation.Title;

			if (dlg.ShowDialog() == true)
			{
				// Find selected writer
				IWriter writer = App.IO.Writers[dlg.FilterIndex - 1];

				if (writer != null)
				{
					DependencyObject config = writer.Configuration;

					if (config is Control)
					{
						// TODO Implement Show Configuration via special Window.ShowDialog()
					}

					_SaveInformation = new SaveInformation()
					{
						Config = config,
						FileName = dlg.FileName,
						Writer = writer
					};

					ApplicationCommands.Save.Execute(null, this);
				}
			}

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the SelectAll command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void SelectAll_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (IsInitialized && PaintAreaHost.IsVisible && Presentation.Slides.Count > 0);
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the SelectAll command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SelectAll_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			PaintArea.EditingMode = InkCanvasEditingMode.Select;
			PaintArea.Select(PaintArea.Strokes);

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the Delete command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Delete_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (PaintArea != null && PaintArea.GetSelectedStrokes().Count > 0);
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the Delete command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Delete_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			PaintArea.Strokes.Remove(PaintArea.GetSelectedStrokes());

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the Undo command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Undo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			//e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the  Undo command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Undo_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			//e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the Redo command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Redo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			//e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the Redo command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Redo_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			//e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the Toggle command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Toggle_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = PaintAreaHost.IsInitialized;
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the Toggle command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Toggle_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			ToggleVisibility();

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecute event of the SaveSelectionToLibrary command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void SaveSelectionToLibrary_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (PaintArea != null && PaintArea.GetSelectedStrokes().Count > 0);
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the SaveSelectionToLibrary command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SaveSelectionToLibrary_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (ShapesLibrary != null)
			{
				StrokeCollection strokes = PaintArea.GetSelectedStrokes();

				PaintArea.Select((StrokeCollection)null);
				ShapesLibrary.Add(new Shape(strokes, string.Format("{0} {1}", ThePresenter.Properties.Resources.DefaultShapeName, ++NewShapeCounter)));

				PaintArea.Select(strokes);
			}
		}

		/// <summary>
		/// Handles the CanExecute event of the NextPage command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void NextPage_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (Presentation != null && Presentation.Slides.Count > 1 && Presentation.SelectedSlide != Presentation.Slides.Last());
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the NextPage command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void NextPage_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Presentation.RequestSlideSelect(Presentation.Slides[Presentation.Slides.IndexOf(Presentation.SelectedSlide) + 1]);
		}

		/// <summary>
		/// Handles the CanExecute event of the PreviousPage command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void PreviousPage_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (Presentation != null && Presentation.Slides.Count > 1 && Presentation.SelectedSlide != Presentation.Slides.First());
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the PreviousPage command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void PreviousPage_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Presentation.RequestSlideSelect(Presentation.Slides[Presentation.Slides.IndexOf(Presentation.SelectedSlide) - 1]);
		}

		/// <summary>
		/// Handles the CanExecute event of the PreviousPage command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void Close_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the PreviousPage command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void Close_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Close();
		}

		/// <summary>
		/// Handles the Executed event of the SetBrushColor command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SetBrushColor_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (e.Parameter is SolidColorBrush)
			{
				DrawingAttributes.Color = ((SolidColorBrush)e.Parameter).Color;
			}
		}

		/// <summary>
		/// Handles the Executed event of the SetIsHighlighter command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SetIsHighlighter_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (e.Parameter is bool)
			{
				DrawingAttributes.IsHighlighter = (bool)e.Parameter;
			}
		}

		/// <summary>
		/// Handles the Executed event of the SetBrushThickness command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SetBrushThickness_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (e.Parameter is double)
			{
				DrawingAttributes.Width = (double)e.Parameter;
				DrawingAttributes.Height = (double)e.Parameter;
			}
		}

		/// <summary>
		/// Handles the Executed event of the SetEditingMode command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SetEditingMode_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (e.Parameter is InkCanvasEditingMode)
			{
				bool reset_after = false;

				if (_DefaultEditingMode.Equals(DrawingAttributes.EditingMode))
					reset_after = true;

				_DefaultEditingMode = (InkCanvasEditingMode)e.Parameter;

				if (reset_after)
					DrawingAttributes.EditingMode = _DefaultEditingMode;
			}
		}

		/// <summary>
		/// Handles the Executed event of the NewPoll command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void NewPoll_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			var win = new CreatePollDialog() { Owner = this, CanvasCandidate = Presentation.SelectedSlide };

			if (win.ShowDialog() == true)
			{
				Poll P = win.Poll;
				Presentation.AddPoll(P);
				CreatedPollsList.SelectedItem = P;
			}

		}

		/// <summary>
		/// HACK: Not used, used for debuging
		/// Handles the Executed event of the SavePolls command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void SavePolls_Executed(object sender, ExecutedRoutedEventArgs e)
		{ 
			Net.PresenterCom.Uids.Uid FakeClientUid1 = new Net.PresenterCom.Uids.Uid();
			Presentation.AddClient(FakeClientUid1, new Net.NetCom.ClientInfo(FakeClientUid1, "FakeClient1"));
			Net.PresenterCom.Uids.Uid FakeClientUid2 = new Net.PresenterCom.Uids.Uid();
			Presentation.AddClient(FakeClientUid2, new Net.NetCom.ClientInfo(FakeClientUid2, "FakeClient2"));

			Poll P = new Poll();
			P.Title = "1Canvas/Canvas Poll";

			P.QuestionData = new ThePresenter.Polls.Data.CanvasQuestionData() { QuestionType = QuestionType.Canvas, Question = "Co je na obrazku?", Size = new Size(30, 30), Background = new byte[] { 0, 0, 0, 0 }, Strokes = new StrokeCollection() };
			P.OptionsData = new ThePresenter.Polls.Data.OptionsData()
			{
				OptionsType = OptionsType.Canvas,
			};

			Presentation.AddPoll(P);

			Poll P2 = new Poll();
			P2.Title = "2Text/Text Poll";

			P2.QuestionData = new ThePresenter.Polls.Data.QuestionData() { QuestionType = QuestionType.Text, Question = "Aka je odpoved na text?" };
			P2.OptionsData = new ThePresenter.Polls.Data.OptionsData()
			{
				OptionsType = OptionsType.Text,
			};

			Presentation.AddPoll(P2);

			Presentation.ProcessPollAnswer(P2.GUID, new TextAnswerData() { Answer = "Vela" }, FakeClientUid1);
			Presentation.ProcessPollAnswer(P2.GUID, new TextAnswerData() { Answer = "Lorem ipsum dolor sit amet consectetuer ac lorem id elit nulla. Lobortis lorem Curabitur dictum quis cursus tortor Ut dolor cursus at. A malesuada Nam consectetuer" }, FakeClientUid2);

			Poll P3 = new Poll();
			P3.Title = "3Text/YesNo Poll";

			P3.QuestionData = new ThePresenter.Polls.Data.QuestionData() { QuestionType = QuestionType.Text, Question = "Aka je odpoved na text?" };
			P3.OptionsData = new ThePresenter.Polls.Data.OptionsData()
			{
				OptionsType = OptionsType.YesNo
			};

			Presentation.AddPoll(P3);

			Poll P5 = new Poll();
			P5.Title = "4Text/PickOne Poll";

			P5.QuestionData = new ThePresenter.Polls.Data.QuestionData() { QuestionType = QuestionType.Text, Question = "Aka je odpoved na text?" };
			P5.OptionsData = new ThePresenter.Polls.Data.SelectOptionsData()
			{
				OptionsType = OptionsType.PickOne,
				Options = new System.Collections.Generic.List<string>(){
					"Option1", "Moznost2", "Option3", "Mznost4"
				}
			};

			Presentation.AddPoll(P5);

			Poll P4 = new Poll();
			P4.Title = "5Text/PickSome Poll";

			P4.QuestionData = new ThePresenter.Polls.Data.QuestionData() { QuestionType = QuestionType.Text, Question = "Aka je odpoved na text?" };
			P4.OptionsData = new ThePresenter.Polls.Data.SelectOptionsData()
			{
				OptionsType = OptionsType.PickSome,
				Options = new System.Collections.Generic.List<string>(){
					"Option1", "Moznost2", "Option3", "Moznost4"
				}
			};

			Presentation.AddPoll(P4);

			Presentation.PublishPoll(P3.GUID);
			Presentation.PublishPoll(P.GUID);
			Presentation.PublishPoll(P4.GUID);
			Presentation.PublishPoll(P2.GUID);
			Presentation.PublishPoll(P5.GUID);
		}

		/// <summary>
		/// Handles the Executed event of the LoadPolls command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void LoadPolls_Executed(object sender, ExecutedRoutedEventArgs e)
		{
		
		}

		/// <summary>
		/// Handles the CanExecute event of the PublishPoll control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void PublishPoll_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (this.CreatedPollsList.SelectedItem is Poll);
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the PublishPoll control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void PublishPoll_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			this.Presentation.PublishPoll((CreatedPollsList.SelectedItem as Poll).GUID);
			e.Handled = true;
		}

		/// <summary>
		/// Handles the Executed event of the AnswerPoll command.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void AnswerPoll_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Poll poll = (Poll)this.PollsList.SelectedItem;

			if (poll.OptionsData.OptionsType == OptionsType.Canvas)
			{
				poll.AnswerData = new CanvasAnswerData(Presentation.SelectedSlide);
			}

			((Poll)this.PollsList.SelectedItem).State = ClientPollState.Answered;

			Presentation.AnswerPoll(poll);

			e.Handled = true;
		}

		/// <summary>
		/// Handles the CanExecuted event of the AnswerPoll control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void AnswerPoll_CanExecuted(object sender, CanExecuteRoutedEventArgs e)
		{
			Poll poll = (Poll)this.PollsList.SelectedItem;

			if (poll == null)
			{
				e.CanExecute = false;
				e.Handled = true;
				return;
			}

			switch (poll.OptionsData.OptionsType)
			{
				case OptionsType.Text:
					String a = (poll.AnswerData as TextAnswerData).Answer;
					e.CanExecute = !(a == null || a.Equals(String.Empty));
					e.Handled = true;
					break;
				case OptionsType.Canvas:
					e.CanExecute = true;
					e.Handled = true;
					return;
				case OptionsType.YesNo:
					e.CanExecute = !((poll.AnswerData as YesNoAnswerData).Result == null);
					e.Handled = true;
					break;
				case OptionsType.PickOne:
					e.CanExecute = !((poll.AnswerData as PickOneAnswerData).SelectedItemIndex == -1);
					e.Handled = true;
					break;
				case OptionsType.PickSome:
					e.CanExecute = true;
					e.Handled = true;
					break;
				default:
					break;
			}
		}
		
		#endregion

		#region Methods

		/// <summary>
		/// Sets <see cref="System.Windows.Controls.InkCanvasEditingMode"/> mode of the <see cref="System.Windows.Controls.InkCanvas"/> based on the <see cref="System.Windows.Input.ModifierKeys"/> pressed on keyboard.
		/// </summary>
		/// <param name="modifier">The <see cref="System.Windows.Input.ModifierKeys"/> pressed on keyboard.</param>
		private void SetEditingMode(ModifierKeys modifier)
		{
			if (IsInitialized)
			{
				if (DrawingAttributes != null && PaintArea != null && PaintArea.IsVisible)
				{
					// Control -> Alt ?
					if (modifier == (ModifierKeys.Control | ModifierKeys.Shift))
						DrawingAttributes.EditingMode = InkCanvasEditingMode.EraseByPoint;
					else if (modifier == ModifierKeys.Control)
						DrawingAttributes.EditingMode = InkCanvasEditingMode.EraseByStroke;
					else if (modifier == ModifierKeys.Shift)
						DrawingAttributes.EditingMode = InkCanvasEditingMode.Select;
					else
						DrawingAttributes.EditingMode = _DefaultEditingMode;
				}
			}
		}

		/// <summary>
		/// Toggles the panel visibility.
		/// </summary>
		/// <param name="panel">The panel.</param>
		/// <param name="value">if set to <c>true</c> panel is Visible, otherwise Collapsed.</param>
		private void TogglePanelVisibility(Dock panel, bool value)
		{
			switch (panel)
			{
				case Dock.Bottom:
					BottomPanel.Visibility = (value ? Visibility.Visible : Visibility.Collapsed);
					break;

				case Dock.Left:
					LeftPanel.Visibility = (value ? Visibility.Visible : Visibility.Collapsed);
					break;

				case Dock.Right:
					RightPanel.Visibility = (value ? Visibility.Visible : Visibility.Collapsed);
					break;

				case Dock.Top:
					break;

				default:
					break;
			}
		}

		/// <summary>
		/// Toggles the visibility of all panels resulting in hiding / showing application.
		/// </summary>
		private void ToggleVisibility()
		{
			if (IsInitialized)
			{
				lock (this)
				{
					bool visible = !PaintAreaHost.IsVisible;

					PaintAreaHost.Visibility = (visible ? Visibility.Visible : Visibility.Collapsed);
					TogglePanelVisibility(Dock.Left, visible);
					TogglePanelVisibility(Dock.Bottom, visible);
					TogglePanelVisibility(Dock.Right, visible);
				}
			}
		}

		#endregion
	}
}
